package com.itxiao.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itxiao.dao.SysRoleMenuDao;
import com.itxiao.dao.SysUserRoleDao;
import com.itxiao.entity.SysMenu;
import com.itxiao.entity.SysRoleMenu;
import com.itxiao.entity.SysUser;
import com.itxiao.entity.SysUserRole;
import com.itxiao.pojo.vo.*;
import com.itxiao.config.RedisKeyConfig;
import com.itxiao.dao.SysMenuDao;

import com.itxiao.service.SysMenuService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (SysMenu)表服务实现类
 *
 * @author makejava
 * @since 2025-09-17 14:33:15
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenu> implements SysMenuService {
    @Resource
    private SysMenuDao sysMenuDao;

    @Resource
    private SysUserRoleDao sysUserRoleDao;
    @Resource
    private SysRoleMenuDao sysRoleMenuDao;
    @Resource
    private StringRedisTemplate template;
    @Override
    public R queryTreeList() {
        List<SysMenu> sysMenuList = sysMenuDao.selectList(null);
        List<SysMenuVo> sysMenuVos = buildMenuTree(sysMenuList);
        return  R.ok(sysMenuVos);

    }
    private List<SysMenuVo> buildMenuTree(List<SysMenu> menuList) {
        // 转换为 ID -> SysMenuVo 的映射，便于快速查找
        Map<Integer, SysMenuVo> menuVoMap = new HashMap<>();
        for (SysMenu menu : menuList) {
            SysMenuVo vo = new SysMenuVo();
            vo.setId(menu.getId());
            vo.setLabel(menu.getTitle());
            vo.setChildren(new ArrayList<>());
            menuVoMap.put(menu.getId(), vo);
        }

        // 存放根节点的列表
        List<SysMenuVo> rootList = new ArrayList<>();

        // 遍历所有菜单，建立父子关系
        for (SysMenu menu : menuList) {
            SysMenuVo currentNode = menuVoMap.get(menu.getId());
            Integer parentId = menu.getParentId();

            // 判断是否为根节点（parentId 为 null 或 0）
            if (parentId == null || parentId == 0) {
                rootList.add(currentNode);
            } else {
                SysMenuVo parentVo = menuVoMap.get(parentId);
                if (parentVo != null) {
                    parentVo.getChildren().add(currentNode);
                }
            }
        }
        return rootList;
    }
    @Override
    public R queryRoleBelongMenu(Integer roleId) {
        if (roleId == null || roleId <= 0) {
            return R.fail("角色ID不能为空");
        }
        List<Integer> menuIds = sysRoleMenuDao.selectList(
                        new QueryWrapper<SysRoleMenu>().eq("role_id", roleId)
                )
                .stream()
                .map(SysRoleMenu::getMenuId)
                .collect(Collectors.toList());

        if (menuIds.isEmpty()) {
            return R.fail("该角色未分配菜单");
        }

        // 2. 根据 menuIds 查询所有对应的菜单信息
        List<SysMenu> menuList = sysMenuDao.selectList(
                new QueryWrapper<SysMenu>().in("id", menuIds)
        );

        if (menuList.isEmpty()) {
            return R.fail("该角色未分配菜单");
        }
        RoleMenuVo roleMenuVo =new RoleMenuVo();

        // 3. 构建树形结构（带排序）
        List<SysMenuVo> tree = buildMenuTree(menuList);
        roleMenuVo.setChildren(tree);
        roleMenuVo.setCheckedKeys(menuIds);
        return R.ok(roleMenuVo);
    }

    @Override
    public R getRouters(String token) {
        // 1. 获取用户
        SysUser sysUser = JSON.parseObject(
                template.opsForValue().get(RedisKeyConfig.AUTH_LOGIN_TOKEN + token),
                SysUser.class
        );
        if (sysUser == null) {return R.fail("登录失效");}

        // 2. 获取角色
        SysUserRole sysUserRole = sysUserRoleDao.selectOne(
                new QueryWrapper<SysUserRole>().eq("user_id", sysUser.getId())
        );
        if (sysUserRole == null) {return R.fail("登录失效");}

        // 3. 获取菜单 ID
        List<Integer> menuIds = sysRoleMenuDao.selectList(
                new QueryWrapper<SysRoleMenu>().eq("role_id", sysUserRole.getRoleId())
        ).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());

        if (menuIds.isEmpty()) {
            return R.ok(Collections.emptyList());
        }

        // 4. 查询菜单
        List<SysMenu> sysMenuList = sysMenuDao.selectList(
                new QueryWrapper<SysMenu>().in("id", menuIds).notIn("menu_type",2)
        );

        if (sysMenuList.isEmpty()) {
            return R.ok(Collections.emptyList());
        }

        // 5. 构建并返回路由树
        List<MenuTreeVo> routerTree = buildMenuTreeFromSysMenu(sysMenuList);

        return R.ok(routerTree);
    }

    private MenuTreeVo convertToMenuTreeVo(SysMenu menu) {
        MenuTreeVo vo = new MenuTreeVo();
        vo.setId(menu.getId());
        vo.setName(menu.getName());
        vo.setPath(menu.getPath());
        vo.setHidden(menu.getHidden());
        vo.setComponent(menu.getComponent());

        MetaBean meta = new MetaBean();
        meta.setTitle(menu.getTitle());
        meta.setIcon(menu.getIcon());
        meta.setIsCache(menu.getIsCache());
        vo.setMeta(meta);

        vo.setChildren(new ArrayList<>());
        return vo;
    }

    private List<MenuTreeVo> buildMenuTreeFromSysMenu(List<SysMenu> sysMenuList) {
        List<SysMenu> visibleMenus = new ArrayList<>(sysMenuList);

        Map<Integer, MenuTreeVo> voMap = new HashMap<>();
        visibleMenus.forEach(menu -> voMap.put(menu.getId(), convertToMenuTreeVo(menu)));

        List<MenuTreeVo> rootList = new ArrayList<>();

        for (SysMenu menu : visibleMenus) {
            MenuTreeVo currentVo = voMap.get(menu.getId());
            Integer parentId = menu.getParentId();

            if (parentId == null || parentId == 0) {
                rootList.add(currentVo);
            } else {
                MenuTreeVo parentVo = voMap.get(parentId);
                if (parentVo != null) {
                    parentVo.getChildren().add(currentVo);
                }
            }
        }

        return rootList;
    }
}

